#pragma once
#include<iostream>
#include<string>
#include<memory>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>

using namespace std;

class tcpClient
{
public:
    tcpClient(const string& serverip, const uint16_t& port)
    :_sockfd(-1)
    ,_serverip(serverip)
    ,_serverport(port)
    {}

    void InitClient()
    {
        // 创建socket(套接字)
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_sockfd < 0)
        {
            // 客户端也是可以弄日志的[类似之前用某些软件崩溃后，会弹出一个是否同意上传日志，]
            // 这里我没弄, 只弄了服务器的日志
            cerr << "socket create error" << endl;
            exit(2);
        }
        cout << "create socket success\n";
        
        //2.bind ip和port【tcp的客户端bind同样不需要显示bind， 由os来管】
        // 并且客户端不需要listen， 所以客户端不需要accept
        // 对于客户端，要向服务器端发起链接，让服务端listen到，然后accept

    }

    void run()
    {
        // 填充结构体，为后来给服务端传输数据做准备
        struct sockaddr_in server;
        bzero(&server, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_serverport);
        server.sin_addr.s_addr = inet_addr(_serverip.c_str());

        // 准备与服务端通信，但tcp通信之前需要先建立链接，对于客户端来说要向服务端发起新链接
        if(connect(_sockfd, (struct sockaddr*)&server, sizeof(server)) != 0)
        {
            //建立链接失败肯定没发继续通信了, 但是也没必要exit
            cerr << "socket connect error" << endl;
        }
        else
        {
            // 成功建立连接之后就可以通信了
            string message;
            while(true)
            {
                cout << "Enter: ";
                getline(cin, message);
                write(_sockfd, message.c_str(), message.size());

                // 还要能接受数据
                char bufferin[1024];
                int n = read(_sockfd, bufferin, sizeof(bufferin)-1);
                if(n > 0)
                {
                    // 读取成功[目前来说，把读取到的数据当字符串，这里还有很多细节没有讲，这和协议有关]
                    bufferin[n] = 0;
                    cout << "server发送: " << bufferin << endl;

                }
                else if(n == 0)
                {
                    cout << "server close" << endl;
                    break;
                }
                else
                {
                    cerr << "read error" << endl;
                    break;
                }
            }
    
        }

    }

    ~tcpClient() 
    {
        if(_sockfd >= 0)
            close(_sockfd); //这里手动关一下，其实服务器进程一关，这个文件描述符也就关了
    }
private:
    int _sockfd;
    string _serverip;
    uint16_t _serverport;
}; 